package com.molichuxing.gateway.bff.payment.services.impl;

import com.molichuxing.framework.contants.RedisKeyConst;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.utils.DateUtil;
import com.molichuxing.framework.utils.RedisLock;
import com.molichuxing.framework.utils.RedisUtil;
import com.molichuxing.gateway.bff.payment.convertor.Convert;
import com.molichuxing.gateway.bff.payment.entity.request.create.OrderPayCreateVo;
import com.molichuxing.gateway.bff.payment.entity.response.CashierDeskVo;
import com.molichuxing.gateway.bff.payment.entity.response.PaymentDetailVo;
import com.molichuxing.gateway.bff.payment.entity.response.PaymentRecordVo;
import com.molichuxing.gateway.bff.payment.services.PaymentBffService;
import com.molichuxing.gateway.contants.PaymentConst;
import com.molichuxing.gateway.utils.PaymentUtil;
import com.molichuxing.services.business.dto.request.create.PaymentBizCreateDto;
import com.molichuxing.services.business.dto.response.*;
import com.molichuxing.services.business.service.OrderBizService;
import com.molichuxing.services.business.service.PaymentBizService;
import com.molichuxing.services.exception.OrderExceptionCodeEnum;
import com.molichuxing.services.infrastructure.dto.response.OrderMileageDto;
import com.molichuxing.services.infrastructure.dto.response.OrderRenegeDto;
import com.molichuxing.services.infrastructure.dto.response.OrderScheduleDto;
import com.molichuxing.services.infrastructure.dto.response.OrderSubscribeSettlementDto;
import com.molichuxing.services.infrastructure.service.OrderMileageService;
import com.molichuxing.services.infrastructure.service.OrderRenegeService;
import com.molichuxing.services.infrastructure.service.OrderScheduleService;
import com.molichuxing.services.infrastructure.service.OrderSubscribeSettlementService;
import com.molichuxing.services.property.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service("paymentBffService")
public class PaymentBffServiceImpl implements PaymentBffService {
	private static final Logger logger = LoggerFactory.getLogger(PaymentBffServiceImpl.class);

	@Value("${profiles.active}")
	private String active;

	@Value("${profiles.active.explain}")
	private String activeExplain;

	@Resource
	private RedisUtil redisUtil;

	@Resource
	private PaymentBizService paymentBizService;

	@Resource
	private OrderBizService orderBizService;

	@Resource
	private OrderMileageService orderMileageService;

	@Resource
	private OrderSubscribeSettlementService orderSubscribeSettlementService;

	@Resource
	private OrderScheduleService orderScheduleService;

	@Resource
	private OrderRenegeService orderRenegeService;

	/**
	 * 收银台
	 * 
	 * @param orderCode
	 *            订单号
	 * @param payType
	 *            支付类型
	 * @param scheduleId
	 *            排期id
	 * @param userId
	 *            用户id
	 * @return
	 */
	@Override
	public CashierDeskVo getCashierDesk(Long orderCode, PaymentCostTypeEnum payType, Integer scheduleId,
			Integer userId) {
		CashierDeskVo result = null;
		// 查询订单信息
		OrderBizDto orderBizDto = orderBizService.getOrder(orderCode);
		if (orderBizDto == null) {
			logger.error("订单({})不存在", orderCode);
			throw new BizException(OrderExceptionCodeEnum.NOT_EXIST.getCode(), "操作失败，订单不存在");
		} else if (!orderBizDto.getUserId().equals(userId)) {
			logger.error("该用户({})无此订单({})", userId, orderCode);
			throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单不存在");
		}
		// 判断订单业务类型
		OrderTypeEnum orderType = orderBizDto.getType();
		if (OrderTypeEnum.EXCLUSIVEL.equals(orderType)) {
			// 专属里程订单
			OrderExclusivelBizDto exclusivelBizDto = (OrderExclusivelBizDto) orderBizDto;
			if (OrderExclusivelStatusEnum.RENEGE_UNPAID.equals(exclusivelBizDto.getOrderStatus())) {
				payType = PaymentCostTypeEnum.RENEGE;
			}
			result = exclusivelCashierDesk(exclusivelBizDto, payType, scheduleId);
		} else if (OrderTypeEnum.SUBSCRIBE.equals(orderType)) {
			// 订阅里程订单
			result = subscribeCashierDesk((OrderSubscribeBizDto) orderBizDto, payType);
		} else if (OrderTypeEnum.RELET_MILEAGE.equals(orderType)) {
			// 加购里程订单
			result = purchaseCashierDesk((OrderMileageBizDto) orderBizDto, payType);
		} else {
			logger.error("订单类型({}:{})错误", orderType.toString(), orderType.getName());
			throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单异常");
		}

		return result;
	}

	private CashierDeskVo purchaseCashierDesk(OrderMileageBizDto purchaseBizDto, PaymentCostTypeEnum payType) {
		CashierDeskVo result = null;
		if (PaymentCostTypeEnum.PURCHASE.equals(payType)) {
			// 加购
			// if
			// (OrderMileagePayStatusEnum.CANCELED.equals(purchaseBizDto.getStatus()))
			// {
			// logger.error("加购订单({})已取消", purchaseBizDto.getOrderCode());
			// throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(),
			// "抱歉，您已超时，订单已失效");
			// } else if
			// (OrderMileagePayStatusEnum.PREPAID.equals(purchaseBizDto.getStatus()))
			// {
			// logger.error("加购订单({})已支付", purchaseBizDto.getOrderCode());
			// throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(),
			// "抱歉，已支付");
			// }

			result = Convert.toCashierDeskVo(purchaseBizDto);
			result.setType(PaymentCostTypeEnum.PURCHASE.getValue());
		} else {
			logger.error("该加购订单({})不存在该类型({}:{})支付", purchaseBizDto.getOrderCode(), payType.toString(),
					payType.getName());
			throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单异常");
		}
		return result;
	}

	private CashierDeskVo subscribeCashierDesk(OrderSubscribeBizDto subscribeBizDto, PaymentCostTypeEnum payType) {
		CashierDeskVo result = null;
		if (PaymentCostTypeEnum.SUBSCRIBE.equals(payType)) {
			// 订购
			// if
			// (!OrderSubscribeStatusEnum.TRADE_UNPAID.equals(subscribeBizDto.getOrderStatus()))
			// {
			// logger.error("订阅订单({})不是待支付状态", subscribeBizDto.getOrderCode());
			// throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(),
			// "操作失败，订单状态已改变");
			// }
			result = Convert.toCashierDeskVo(subscribeBizDto);
			result.setType(PaymentCostTypeEnum.SUBSCRIBE.getValue());
		} else if (PaymentCostTypeEnum.RENEW.equals(payType)) {
			// 续订
			// if
			// (!OrderSubscribeStatusEnum.TRADE_UNPAID.equals(subscribeBizDto.getOrderStatus()))
			// {
			// logger.error("订阅订单({})不是待支付状态", subscribeBizDto.getOrderCode());
			// throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(),
			// "操作失败，订单状态已改变");
			// }
			result = Convert.toCashierDeskVo(subscribeBizDto);
			result.setType(PaymentCostTypeEnum.RENEW.getValue());
		} else if (PaymentCostTypeEnum.SETTLEMENT.equals(payType)) {
			// 结算
			OrderSubscribeSettlementDto settlementDto = orderSubscribeSettlementService
					.getOrderSubscribeSettlement(subscribeBizDto.getOrderCode());
			if (settlementDto == null) {
				logger.error("该订阅订单({})不存在结算信息", subscribeBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单不存在结算");
			} else if (OrderSubscribeSettlementPayStatusEnum.PREPAID.equals(settlementDto.getStatus())) {
				logger.error("该订阅订单({})结算已支付", subscribeBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，已支付");
			}
			result = Convert.toCashierDeskVo(settlementDto);
			result.setType(PaymentCostTypeEnum.SETTLEMENT.getValue());
		} else {
			logger.error("该订单({})不存在该类型({}:{})支付", subscribeBizDto.getOrderCode(), payType.toString(),
					payType.getName());
			throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单异常");
		}
		return result;
	}

	private CashierDeskVo exclusivelCashierDesk(OrderExclusivelBizDto exclusivelBizDto, PaymentCostTypeEnum payType,
			Integer scheduleId) {
		CashierDeskVo result = null;
		if (PaymentCostTypeEnum.SUBSCRIBE.equals(payType)) {
			// 订购
			// if
			// (!OrderExclusivelStatusEnum.TRADE_UNPAID.equals(exclusivelBizDto.getOrderStatus()))
			// {
			// logger.error("专属订单({})不是待支付状态", exclusivelBizDto.getOrderCode());
			// throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(),
			// "操作失败，订单状态已改变");
			// }
			result = Convert.toCashierDeskVo(exclusivelBizDto);
			result.setType(PaymentCostTypeEnum.SUBSCRIBE.getValue());
		} else if (PaymentCostTypeEnum.REPAYMENT.equals(payType)) {
			// 还款
			OrderScheduleDto orderScheduleDto = orderScheduleService.getOrderSchedule(scheduleId);
			if (orderScheduleDto == null) {
				logger.error("专属订单({})排期({})不存在", exclusivelBizDto.getOrderCode(), scheduleId);
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单排期不存在");
			} else if (!orderScheduleDto.getOrderCode().equals(exclusivelBizDto.getOrderCode())) {
				logger.error("专属订单排期({})订单号({})不属于查询支付订单({})", scheduleId, orderScheduleDto.getOrderCode(),
						exclusivelBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单排期不存在");
			} else if (!OrderScheduleStatusEnum.NO.equals(orderScheduleDto.getStatus())) {
				logger.error("专属订单({})排期({})已支付", exclusivelBizDto.getOrderCode(), scheduleId);
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，该期已还款");
			}
			// 查询上一个排期
			OrderScheduleDto preScheduleDto = orderScheduleService
					.getOrderScheduleByPeriods(orderScheduleDto.getOrderCode(), orderScheduleDto.getPeriods() - 1);
			if (!OrderScheduleStatusEnum.ALREADY.equals(preScheduleDto.getStatus())) {
				logger.error("专属订单({})排期({})上一期未支付", exclusivelBizDto.getOrderCode(), scheduleId);
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单上一期还未还款");
			}
			result = Convert.toCashierDeskVo(orderScheduleDto);
			result.setType(PaymentCostTypeEnum.REPAYMENT.getValue());
		} else if (PaymentCostTypeEnum.RENEGE.equals(payType)) {
			// 退租缴费
			OrderRenegeDto orderRenegeDto = orderRenegeService.getRenege(exclusivelBizDto.getOrderCode(),
					OrderRenegeStatusEnum.RENEGE);
			if (orderRenegeDto == null) {
				logger.error("专属订单({})不存在退租信息", exclusivelBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，该订单不存在退租信息");
			}
			result = Convert.toCashierDeskVo(orderRenegeDto);
			result.setType(PaymentCostTypeEnum.RENEGE.getValue());
		} else {
			logger.error("该专属订单({})不存在该类型({}:{})支付", exclusivelBizDto.getOrderCode(), payType.toString(),
					payType.getName());
			throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单异常");
		}
		return result;
	}

	/**
	 * 支付-生成预支付单
	 * 
	 * @param createVo
	 * @return
	 */
	@Override
	public String getOrderPay(OrderPayCreateVo createVo) throws BizException, Exception {
		String result = null;
		// 根据订单号查询订单信息
		OrderBizDto orderBizDto = orderBizService.getOrder(createVo.getOrderCode());
		if (orderBizDto == null) {
			logger.error("订单({})不存在", createVo.getOrderCode());
			throw new BizException(OrderExceptionCodeEnum.NOT_EXIST.getCode(), "操作失败，订单不存在");
		} else if (!orderBizDto.getUserId().equals(createVo.getOperateId())) {
			logger.error("该用户({})无此订单({})", createVo.getOperateId(), createVo.getOrderCode());
			throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单不存在");
		}

		RedisLock lock = new RedisLock(redisUtil,
				RedisKeyConst.LOCK_TOKEN_KEY + "payment_" + orderBizDto.getOrderCode() + "_" + orderBizDto.getUserId(), 10000);

		if (lock.tryLock()) {
			try {
				// 判断订单业务类型
				OrderTypeEnum orderType = orderBizDto.getType();
				if (OrderTypeEnum.EXCLUSIVEL.equals(orderType)) {
					// 专属里程订单
					OrderExclusivelBizDto orderExclusivelBizDto = (OrderExclusivelBizDto) orderBizDto;
					if (OrderExclusivelStatusEnum.RENEGE_UNPAID.equals(orderExclusivelBizDto.getOrderStatus())) {
						createVo.setPayType(PaymentCostTypeEnum.RENEGE.getValue());
					}
					result = exclusivelOrderPay(orderExclusivelBizDto, createVo);
				} else if (OrderTypeEnum.SUBSCRIBE.equals(orderType)) {
					// 订阅里程订单
					result = subscribeOrderPay((OrderSubscribeBizDto) orderBizDto, createVo);
				} else if (OrderTypeEnum.RELET_MILEAGE.equals(orderType)) {
					// 加购里程订单
					result = purchaseOrderPay((OrderMileageBizDto) orderBizDto, createVo);
				} else {
					logger.error("订单类型({}:{})错误", orderType.toString(), orderType.getName());
					throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单异常");
				}
			} finally {
				lock.unlock();
			}
		} else {
			Thread.sleep(3000);
			throw new BizException("请勿重复提交");
		}

		return result;
	}

	private String purchaseOrderPay(OrderMileageBizDto orderBizDto, OrderPayCreateVo createVo)
			throws BizException, Exception {
		PaymentBizCreateDto createDto = null;

		PaymentCostTypeEnum costType = PaymentCostTypeEnum.getEnum(createVo.getPayType());
		if (PaymentCostTypeEnum.PURCHASE.equals(costType)) {
			// 加购
			if (OrderMileagePayStatusEnum.CANCELED.equals(orderBizDto.getStatus())) {
				logger.error("加购订单({})已取消", orderBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "抱歉，您已超时，订单已失效");
			} else if (OrderMileagePayStatusEnum.PREPAID.equals(orderBizDto.getStatus())) {
				logger.error("加购订单({})已支付", orderBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "抱歉，已支付");
			}
			// 判断金额
			BigDecimal payAmount = orderBizDto.getPurchaseFee().add(orderBizDto.getBeyondFee());
			if (!PaymentUtil.checkAmount(createVo, payAmount, redisUtil.get(PaymentConst.TEST_CPU_REDIS_KEY))) {
				logger.error("订单({})金额({})和前端金额({})不一致", createVo.getOrderCode(), payAmount, createVo.getPayAmount());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，支付金额异常");
			}
			// TODO 判断里程?

			createDto = Convert.toPaymentBizCreateDto(orderBizDto, createVo, payAmount, costType);
		} else {
			logger.error("该加购订单({})不存在该类型({}:{})支付", orderBizDto.getOrderCode(), costType.toString(),
					costType.getName());
			throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单异常");
		}
		return paymentBizService.getOrderPay(createDto);
	}

	private String subscribeOrderPay(OrderSubscribeBizDto orderBizDto, OrderPayCreateVo createVo)
			throws BizException, Exception {
		PaymentBizCreateDto createDto = null;

		PaymentCostTypeEnum costType = PaymentCostTypeEnum.getEnum(createVo.getPayType());
		if (!PaymentCostTypeEnum.SETTLEMENT.equals(costType) && orderBizDto.getParentOrderCode() != null) {
			costType = PaymentCostTypeEnum.RENEW;
		}
		if (PaymentCostTypeEnum.SUBSCRIBE.equals(costType)) {
			// 验证是否有订单
			if (verifyHasOtherOrder(orderBizDto.getOrderCode(), orderBizDto.getUserId())) {
				// 存在
				logger.error("订单(" + orderBizDto.getOrderCode() + ")支付验证存在其他未结束订单");
				throw new BizException("抱歉，您名下已有订单尚未完成，请勿支付");
			}

			// 订购
			if (!OrderSubscribeStatusEnum.TRADE_UNPAID.equals(orderBizDto.getOrderStatus())) {
				logger.error("订单({})不是待支付状态", orderBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单状态已改变");
			}
			// 判断金额
			BigDecimal payAmount = orderBizDto.getCartFee().add(orderBizDto.getDeposit());
			if (!PaymentUtil.checkAmount(createVo, payAmount, redisUtil.get(PaymentConst.TEST_CPU_REDIS_KEY))) {
				logger.error("订单({})金额({})和前端金额({})不一致", createVo.getOrderCode(), payAmount, createVo.getPayAmount());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，支付金额异常");
			}
			createDto = Convert.toPaymentBizCreateDto(orderBizDto, createVo, payAmount, costType, null);
		} else if (PaymentCostTypeEnum.RENEW.equals(costType)) {
			// 续订
			if (!OrderSubscribeStatusEnum.TRADE_UNPAID.equals(orderBizDto.getOrderStatus())) {
				logger.error("订单({})不是待支付状态", orderBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单状态已改变");
			}
			// 判断金额
			BigDecimal payAmount = orderBizDto.getCartFee().add(orderBizDto.getDeposit());
			if (!PaymentUtil.checkAmount(createVo, payAmount, redisUtil.get(PaymentConst.TEST_CPU_REDIS_KEY))) {
				logger.error("订单({})金额({})和前端金额({})不一致", createVo.getOrderCode(), payAmount, createVo.getPayAmount());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，支付金额异常");
			}
			createDto = Convert.toPaymentBizCreateDto(orderBizDto, createVo, payAmount, costType, null);
		} else if (PaymentCostTypeEnum.SETTLEMENT.equals(costType)) {
			// 结算
			OrderSubscribeSettlementDto settlementDto = orderSubscribeSettlementService
					.getOrderSubscribeSettlement(orderBizDto.getOrderCode());
			if (settlementDto == null) {
				logger.error("该订单({})不存在结算信息", orderBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单不存在结算");
			} else if (OrderSubscribeSettlementPayStatusEnum.PREPAID.equals(settlementDto.getStatus())) {
				logger.error("该订单({})结算已支付", orderBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，已支付");
			}
			// 判断金额
			BigDecimal payAmount = settlementDto.getTotalFee();
			if (!PaymentUtil.checkAmount(createVo, payAmount, redisUtil.get(PaymentConst.TEST_CPU_REDIS_KEY))) {
				logger.error("订单({})金额({})和前端金额({})不一致", createVo.getOrderCode(), payAmount, createVo.getPayAmount());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，支付金额异常");
			}
			createDto = Convert.toPaymentBizCreateDto(orderBizDto, createVo, payAmount, costType, settlementDto);
		} else {
			logger.error("该订单({})不存在该类型({}:{})支付", orderBizDto.getOrderCode(), costType.toString(), costType.getName());
			throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单异常");
		}
		return paymentBizService.getOrderPay(createDto);
	}

	private String exclusivelOrderPay(OrderExclusivelBizDto orderBizDto, OrderPayCreateVo createVo)
			throws BizException, Exception {
		PaymentBizCreateDto createDto = null;

		PaymentCostTypeEnum costType = PaymentCostTypeEnum.getEnum(createVo.getPayType());
		if (PaymentCostTypeEnum.SUBSCRIBE.equals(costType)) {
			// 验证是否有订单
			if (verifyHasOtherOrder(orderBizDto.getOrderCode(), orderBizDto.getUserId())) {
				// 存在
				logger.error("订单(" + orderBizDto.getOrderCode() + ")支付验证存在其他未结束订单");
				throw new BizException("抱歉，您名下已有订单尚未完成，请勿支付");
			}

			// 订购
			if (!OrderExclusivelStatusEnum.TRADE_UNPAID.equals(orderBizDto.getOrderStatus())) {
				logger.error("订单({})不是待支付状态", orderBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单状态已改变");
			}
			BigDecimal payAmount = OrderPaymentMethodEnum.FULL.equals(orderBizDto.getPaymentMethod())
					? orderBizDto.getCartFee().add(orderBizDto.getDeposit())
					: orderBizDto.getRental().add(orderBizDto.getDeposit());
			// 判断金额
			if (!PaymentUtil.checkAmount(createVo, payAmount, redisUtil.get(PaymentConst.TEST_CPU_REDIS_KEY))) {
				logger.error("订单订购({})金额({})和前端金额({})不一致", createVo.getOrderCode(), payAmount, createVo.getPayAmount());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，支付金额异常");
			}
			// 总期数
			Integer totalPeriods = orderBizDto.getTransportTime() / orderBizDto.getRepaymentPeriod();
			createDto = Convert.toPaymentBizCreateDto(orderBizDto, createVo, payAmount, 0, 1,
					totalPeriods, costType);
		} else if (PaymentCostTypeEnum.REPAYMENT.equals(costType)) {
			// 还款
			OrderScheduleDto orderScheduleDto = orderScheduleService.getOrderSchedule(createVo.getScheduleId());
			if (orderScheduleDto == null) {
				logger.error("订单({})排期({})不存在", orderBizDto.getOrderCode(), createVo.getScheduleId());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单排期不存在");
			} else if (!orderScheduleDto.getOrderCode().equals(orderBizDto.getOrderCode())) {
				logger.error("排期({})订单号({})不属于查询支付订单({})", createVo.getScheduleId(), orderScheduleDto.getOrderCode(),
						orderBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单排期不存在");
			} else if (!OrderScheduleStatusEnum.NO.equals(orderScheduleDto.getStatus())) {
				logger.error("订单({})排期({})已支付", orderBizDto.getOrderCode(), createVo.getScheduleId());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，该期已还款");
			}
			// 查询上一个排期
			OrderScheduleDto preScheduleDto = orderScheduleService
					.getOrderScheduleByPeriods(orderScheduleDto.getOrderCode(), orderScheduleDto.getPeriods() - 1);
			if (!OrderScheduleStatusEnum.ALREADY.equals(preScheduleDto.getStatus())) {
				logger.error("订单({})排期({})上一期未支付", orderBizDto.getOrderCode(), createVo.getScheduleId());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单上一期还未还款");
			}
			BigDecimal payAmount = orderScheduleDto.getPayable();
			// 判断金额
			if (!PaymentUtil.checkAmount(createVo, payAmount, redisUtil.get(PaymentConst.TEST_CPU_REDIS_KEY))) {
				logger.error("订单还款({})金额({})和前端金额({})不一致", createVo.getOrderCode(), payAmount, createVo.getPayAmount());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，支付金额异常");
			}

			createDto = Convert.toPaymentBizCreateDto(orderBizDto, createVo, payAmount, orderScheduleDto.getId(),
					orderScheduleDto.getPeriods(), orderScheduleDto.getTotalPeriods(), costType);
		} else if (PaymentCostTypeEnum.RENEGE.equals(costType)) {
			// 退租缴费
			OrderRenegeDto orderRenegeDto = orderRenegeService.getRenege(orderBizDto.getOrderCode(),
					OrderRenegeStatusEnum.RENEGE);
			if (orderRenegeDto == null) {
				logger.error("专属订单({})不存在退租信息", orderBizDto.getOrderCode());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，该订单不存在退租信息");
			}
			// 判断金额
			if (!PaymentUtil.checkAmount(createVo, orderRenegeDto.getCostAmount(),
					redisUtil.get(PaymentConst.TEST_CPU_REDIS_KEY))) {
				logger.error("订单退租缴费({})金额({})和前端金额({})不一致", createVo.getOrderCode(), orderRenegeDto.getCostAmount(),
						createVo.getPayAmount());
				throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，支付金额异常");
			}
			createDto = Convert.toPaymentBizCreateDto(orderBizDto, createVo, orderRenegeDto.getCostAmount(), 0, 0, 0,
					costType);
		} else {
			logger.error("该订单({})不存在该类型({}:{})支付", orderBizDto.getOrderCode(), costType.toString(), costType.getName());
			throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "操作失败，订单异常");
		}

		return paymentBizService.getOrderPay(createDto);
	}

	/**
	 * 验证是否存在其他为结束订单
	 *
	 * @param orderCode 当前订单号
	 * @param userId    用户id
	 * @return
	 */
	private boolean verifyHasOtherOrder(Long orderCode, Integer userId) {
		// 根据用户查询订单信息
		List<OrderMemberBizDto> orders = orderBizService.getNormalOrderByUser(userId);
		if (orders == null || orders.isEmpty()) {
			return false;
		}

		for (OrderMemberBizDto order : orders) {
			if (order.getOrderCode().equals(orderCode)) {
				continue;
			}
			if (OrderTypeEnum.EXCLUSIVEL.equals(order.getType())) {
				// 专属
				OrderExclusivelBizDto exclusivelBizDto = (OrderExclusivelBizDto) order;
				if (!(OrderExclusivelStatusEnum.TRADE_CANCELED.equals(exclusivelBizDto.getOrderStatus())
						|| OrderExclusivelStatusEnum.TRADE_FINISH.equals(exclusivelBizDto.getOrderStatus())
						|| OrderExclusivelStatusEnum.RENEGE_FINISH.equals(exclusivelBizDto.getOrderStatus()))) {
					return true;
				}
			} else if (OrderTypeEnum.SUBSCRIBE.equals(order.getType())) {
				// 订阅
				OrderSubscribeBizDto subscribeBizDto = (OrderSubscribeBizDto) order;
				if (!(OrderSubscribeStatusEnum.TRADE_CANCELED.equals(subscribeBizDto.getOrderStatus())
						|| OrderSubscribeStatusEnum.TRADE_FINISH.equals(subscribeBizDto.getOrderStatus())
						|| OrderSubscribeStatusEnum.RETURN_FINISH.equals(subscribeBizDto.getOrderStatus()))) {
					return true;
				}
			}
		}

		return false;
	}

	/**
	 * 用户支付记录
	 *
	 * @param userId 用户id
	 * @return
	 */
	@Override
	public List<PaymentRecordVo> getPaymentRecord(Integer userId) {
		List<PaymentRecordVo> result = null;
		List<PaymentRecordBizDto> paymentRecordBizDtos = paymentBizService.getPaymentRecord(userId);
		if (paymentRecordBizDtos == null || paymentRecordBizDtos.isEmpty()) {
			return result;
		}
		DecimalFormat df = new DecimalFormat("#,###.##");
		result = new ArrayList<>();
		for (PaymentRecordBizDto paymentRecordBizDto : paymentRecordBizDtos) {
			PaymentRecordVo paymentRecordVo = Convert.toPaymentRecordVo(paymentRecordBizDto, df);
			// 支付详情
			paymentRecordVo.setPaymentDetails(paymentDetails(paymentRecordBizDto, df));
			result.add(paymentRecordVo);
		}

		return result;
	}

	private List<PaymentDetailVo> paymentDetails(PaymentRecordBizDto paymentRecordBizDto, DecimalFormat df) {
		List<PaymentDetailVo> result = null;
		// 支付详情
		Map<PaymentDetailTypeEnum, PaymentDetailBizDto> paymentDetailMap = paymentRecordBizDto.getPaymentDetailMap();
		if (paymentDetailMap == null || paymentDetailMap.isEmpty()) {
			return result;
		}
		result = new ArrayList<>();
		result.add(new PaymentDetailVo("支付单号", paymentRecordBizDto.getPayNumber()));
		result.add(new PaymentDetailVo("订单号", paymentRecordBizDto.getOrderCode().toString()));
		result.add(new PaymentDetailVo("交易流水号", paymentRecordBizDto.getThirdPayNumber()));
		result.add(new PaymentDetailVo("支付时间", DateUtil.formatTime(paymentRecordBizDto.getPayTime())));
		result.add(new PaymentDetailVo("支付方式", PaymentUtil.transUserPayWay(paymentRecordBizDto.getPayWay())));
		if (PaymentBusinessTypeEnum.EXCLUSIVEL.equals(paymentRecordBizDto.getBusinessType())) {
			// 专属订单
			if (PaymentCostTypeEnum.RENEGE.equals(paymentRecordBizDto.getCostType())) {
				// 退租
				PaymentDetailBizDto paymentDetailBizDto = paymentDetailMap.get(PaymentDetailTypeEnum.RENEGE_FEE);
				result.add(new PaymentDetailVo("退租违约金",
						paymentDetailBizDto == null ? null
								: "¥" + paymentDetailMap.get(PaymentDetailTypeEnum.RENEGE_FEE)
						.getAmount().stripTrailingZeros().toPlainString()));
			} else {
				result.add(new PaymentDetailVo("租车费",
						"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.CART_FEE).getAmount().stripTrailingZeros()
								.toPlainString()));
				if (!PaymentCostTypeEnum.REPAYMENT.equals(paymentRecordBizDto.getCostType())
						&& paymentDetailMap.get(PaymentDetailTypeEnum.DEPOSIT) != null) {
					result.add(new PaymentDetailVo("保证金", "¥" + paymentDetailMap.get(PaymentDetailTypeEnum.DEPOSIT)
							.getAmount().stripTrailingZeros().toPlainString()));
				}
			}

		} else if (PaymentBusinessTypeEnum.SUBSCRIBE.equals(paymentRecordBizDto.getBusinessType())) {
			// 订阅订单
			if (PaymentCostTypeEnum.SUBSCRIBE.equals(paymentRecordBizDto.getCostType())) {
				// 订购
				result.add(new PaymentDetailVo("租车费",
						"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.CART_FEE).getAmount().stripTrailingZeros()
								.toPlainString()));
				result.add(new PaymentDetailVo("基础里程费",
						"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.BASE_MILEAGE_FEE).getAmount()
								.stripTrailingZeros().toPlainString()));
				result.add(new PaymentDetailVo("订阅里程费",
						"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.PACKAGE_MILEAGE_FEE).getAmount()
								.stripTrailingZeros().toPlainString()));
				result.add(new PaymentDetailVo("保证金",
						"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.DEPOSIT).getAmount().stripTrailingZeros()
								.toPlainString()));
			} else if (PaymentCostTypeEnum.RENEW.equals(paymentRecordBizDto.getCostType())) {
				// 续订
				result.add(new PaymentDetailVo("租车费",
						"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.CART_FEE).getAmount().stripTrailingZeros()
								.toPlainString()));
				result.add(new PaymentDetailVo("基础里程费",
						"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.BASE_MILEAGE_FEE).getAmount()
								.stripTrailingZeros().toPlainString()));
				result.add(new PaymentDetailVo("订阅里程费",
						"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.PACKAGE_MILEAGE_FEE).getAmount()
								.stripTrailingZeros().toPlainString()));
			} else if (PaymentCostTypeEnum.PURCHASE.equals(paymentRecordBizDto.getCostType())) {
				// 加购
				// 查询加购信息
				OrderMileageDto orderMileageDto = orderMileageService
						.getOrderMileage(paymentRecordBizDto.getOrderCode());
				if (orderMileageDto.getBeyondFee() != null
						&& orderMileageDto.getBeyondFee().compareTo(BigDecimal.ZERO) > 0) {
					result.add(new PaymentDetailVo(
							"超里程费用",
							"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.BEYOND_MILEAGE_FEE).getAmount()
									.stripTrailingZeros().toPlainString() + "(" + orderMileageDto.getBeyondMileage() + "公里 x "
											+ orderMileageDto.getBeyondMileageUnitPrice().stripTrailingZeros().toPlainString()
									+ "元)"));
				}
				result.add(new PaymentDetailVo("订阅里程费",
						"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.ADD_MILEAGE_FEE).getAmount()
								.stripTrailingZeros().toPlainString()));

			} else if (PaymentCostTypeEnum.SETTLEMENT.equals(paymentRecordBizDto.getCostType())) {
				// 结算
				// 查询结算信息
				OrderSubscribeSettlementDto orderSubscribeSettlementDto = orderSubscribeSettlementService
						.getOrderSubscribeSettlement(paymentRecordBizDto.getOrderCode());
				// 是否有超里程费用
				if (orderSubscribeSettlementDto.getBeyondMileageFee() != null
						&& orderSubscribeSettlementDto.getBeyondMileageFee().compareTo(BigDecimal.ZERO) > 0) {
					result.add(new PaymentDetailVo(
							"超里程费用",
							"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.BEYOND_MILEAGE_FEE).getAmount()
									.stripTrailingZeros().toPlainString() + "("
									+ orderSubscribeSettlementDto.getBeyondMileage() + "公里 x "
									+ orderSubscribeSettlementDto.getBeyondMileageUnitPrice().stripTrailingZeros()
											.toPlainString()
									+ "元)"));
				}
				// 是否有超时费用
				if (orderSubscribeSettlementDto.getBeyondDayFee() != null
						&& orderSubscribeSettlementDto.getBeyondDayFee().compareTo(BigDecimal.ZERO) > 0) {
					result.add(new PaymentDetailVo(
							"超时费用",
							"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.TIME_OUT_FEE).getAmount()
									.stripTrailingZeros().toPlainString() + "("
									+ orderSubscribeSettlementDto.getBeyondDay() + "天 x "
									+ orderSubscribeSettlementDto.getBeyondDayUnitPrice().stripTrailingZeros()
											.toPlainString()
									+ "元)"));
				}
				// 是否有质损费用
				if (orderSubscribeSettlementDto.getDamageFee() != null
						&& orderSubscribeSettlementDto.getDamageFee().compareTo(BigDecimal.ZERO) > 0) {
					result.add(new PaymentDetailVo("质损费用",
							"¥" + paymentDetailMap.get(PaymentDetailTypeEnum.QUALITY_LOSS).getAmount()
									.stripTrailingZeros().toPlainString()));
				}
			}
		}
		result.add(new PaymentDetailVo("备注", paymentRecordBizDto.getRemark()));
		return result;
	}

}
